//
// Created by 77873 on 2020/10/10 0010.
//

#include "CallBackToJava.h"


CallBackToJava::CallBackToJava(JavaVM *vm, JNIEnv *env, jobject *obj) {
    this->javaVM = vm;
    this->jniEnv = env;
    this->jobj = *obj;
    this->jobj = env->NewGlobalRef(jobj);


    jclass jlz = jniEnv->GetObjectClass(jobj);

    if (!jlz) {
        if (LOG_DEBUG) {
            LOGE("GetObjectClass is error");
        }
        return;
    }

    /**第一个参数为   jni层获取的class对象, 第二个为需要回调的方法名，第三个为回调方法所需要的参数，
     * ()表示方法， V 表示返回值 为VOID
     *
     * int类型的参数  则在()中写上 (I)
     * 布尔值类型的参数 则在()中写上，(Z)
     * String类型的参数  Ljava/lang/String;
     * byte[] 数组参数 [B
      *
     *
     * */
    jmid_parpared = env->GetMethodID(jlz, "OnParpared", "()V");
    jmid_error = env->GetMethodID(jlz, "OnError", "(ILjava/lang/String;)V");
    jmid_load = env->GetMethodID(jlz, "OnLoad", "(Z)V");
    jmid_complete = env->GetMethodID(jlz, "OnDecodecComplete", "()V");
    jmid_videoTimeInfo=env->GetMethodID(jlz,"onCallTimeInfo","(II)V");
    jmid_renderYuv = env->GetMethodID(jlz, "onCallRenderYuv", "(II[B[B[B)V");
    jmid_isSupportMediaCodec=env->GetMethodID(jlz,"onCllIsSupportMediaCodec",
            "(Ljava/lang/String;)Z");
    jmid_initMediaCodec=env->GetMethodID(jlz,"initMiediaCodec","(Ljava/lang/String;II[B[B)V");

    jmid_decodecAvpacket=env->GetMethodID(jlz,"decodecAvpacket","(I[B)V");

}

CallBackToJava::~CallBackToJava() {

}


void CallBackToJava::OnCallError(int type, int code, char *msg) {
    if (type == MAIN_THREAD) {
        jstring jmsg = jniEnv->NewStringUTF(msg);
        jniEnv->CallVoidMethod(jobj, jmid_error, code, jmsg);
    } else {
        JNIEnv *currentEnv = NULL;
        if (javaVM->AttachCurrentThread(&currentEnv, 0) != JNI_OK) {
            LOGE("javaVm AttachCurrentThread on error");
            return;
        }
        jstring jmsg = currentEnv->NewStringUTF(msg);
        currentEnv->CallVoidMethod(jobj, jmid_error, code, jmsg);
        javaVM->DetachCurrentThread();
    }
}


void CallBackToJava::OnCallParpared(int type) {
    if (type == MAIN_THREAD) {//如果在主线程
        jniEnv->CallVoidMethod(jobj, jmid_parpared);
    } else if (type == CHILD_THREAD) {
        JNIEnv *currentEnv = NULL;
        if (javaVM->AttachCurrentThread(&currentEnv, 0) != JNI_OK) {
            LOGE("javaVm AttachCurrentThread on error");
            return;
        }
        LOGE("currentEnv callVoidMethod");
        currentEnv->CallVoidMethod(jobj, jmid_parpared);
        javaVM->DetachCurrentThread();
    }
}

void CallBackToJava::OnCallComplete(int type) {
    if (type == MAIN_THREAD) {//如果在主线程
        jniEnv->CallVoidMethod(jobj, jmid_complete);
    } else {
        //如果在子线程，需要获取到 当前线程的 jnienv对象
        JNIEnv *currentEnv = NULL;
        if (javaVM->AttachCurrentThread(&currentEnv, 0) != JNI_OK) {
            LOGE("javaVm AttachCurrentThread on error");
            return;
        }
        currentEnv->CallVoidMethod(jobj, jmid_complete);
        javaVM->DetachCurrentThread();
    }
}

void CallBackToJava::onCallLoad(int type, bool isLoad) {
    if (type == MAIN_THREAD) {
        jniEnv->CallVoidMethod(jobj, jmid_load, isLoad);
    } else {
        JNIEnv *currentEnv = NULL;
        if (javaVM->AttachCurrentThread(&currentEnv, 0) != JNI_OK) {
            LOGE("javaVm AttachCurrentThread on error");
            return;
        }
        currentEnv->CallVoidMethod(jobj, jmid_load, isLoad);
        javaVM->DetachCurrentThread();
    }
}

void CallBackToJava::onCallTimeInfo(int type, int currentTime, int totalTime) {

    if(type==MAIN_THREAD){
        jniEnv->CallVoidMethod(jobj,jmid_videoTimeInfo,currentTime,totalTime);
    } else if(type==CHILD_THREAD){
        JNIEnv *currentEnv=NULL;
        if(javaVM->AttachCurrentThread(&currentEnv,0)!=JNI_OK){
            LOGE("javaVm AttachCurrentThread failed");
            return;
        }
        currentEnv->CallVoidMethod(jobj,jmid_videoTimeInfo,currentTime,totalTime);
        javaVM->DetachCurrentThread();
    }
}


void CallBackToJava::onCallRenderYuv(int width, int height, uint8_t *fy, uint8_t *fu, uint8_t *fv) {
    JNIEnv *jniEnv;
    if (javaVM->AttachCurrentThread(&jniEnv, 0) != JNI_OK) {
        LOGE("call onCallRenderYuv worng");
        return;
    }

    jbyteArray y = jniEnv->NewByteArray(width * height);
    jniEnv->SetByteArrayRegion(y, 0,width*height, reinterpret_cast<const jbyte *>(fy));

    jbyteArray u = jniEnv->NewByteArray(width * height/4);
    jniEnv->SetByteArrayRegion(u, 0,width*height/4, reinterpret_cast<const jbyte *>(fu));

    jbyteArray v = jniEnv->NewByteArray(width * height/4);
    jniEnv->SetByteArrayRegion(v, 0,width*height/4, reinterpret_cast<const jbyte *>(fv));

    jniEnv->CallVoidMethod(jobj,jmid_renderYuv,width,height,y,u,v);

    jniEnv->DeleteLocalRef(y);
    jniEnv->DeleteLocalRef(u);
    jniEnv->DeleteLocalRef(v);

    javaVM->DetachCurrentThread();
}

bool CallBackToJava::onCllIsSupportMediaCodec(const char *Name) {

    bool  isSupport= false;
    JNIEnv *currentEnv;
    if (javaVM->AttachCurrentThread(&currentEnv, 0) != JNI_OK) {
        LOGE("call onCllIsSupportMediaCodec worng");
        return isSupport;
    }

    jstring  codecName=currentEnv->NewStringUTF(Name);
    isSupport=currentEnv->CallBooleanMethod(jobj,jmid_isSupportMediaCodec,codecName);

    currentEnv->DeleteLocalRef(codecName);

    javaVM->DetachCurrentThread();
    return isSupport;
}

void CallBackToJava::onCallInitMediaCodec(const char *codec, int width, int height,
        int csd0_size,int csd1_size,
        uint8_t *csd_0,uint8_t *csd_1) {

    JNIEnv *currentEnv;
    if (javaVM->AttachCurrentThread(&currentEnv, 0) != JNI_OK) {
        LOGE("call onCallInitMediaCodec worng");
    }

    jstring codecName =currentEnv->NewStringUTF(codec);

    jbyteArray  csd0=currentEnv->NewByteArray(csd0_size);
    currentEnv->SetByteArrayRegion(csd0, 0, csd0_size, reinterpret_cast<const jbyte *>(csd_0));

    jbyteArray  csd1=currentEnv->NewByteArray(csd1_size);
    currentEnv->SetByteArrayRegion(csd1, 0, csd1_size, reinterpret_cast<const jbyte *>(csd_1));


    currentEnv->CallVoidMethod(jobj,jmid_initMediaCodec,codecName,width,height,csd0,csd1);

    currentEnv->DeleteLocalRef(codecName);
    currentEnv->DeleteLocalRef(csd0);
    currentEnv->DeleteLocalRef(csd1);

    javaVM->DetachCurrentThread();
}

void CallBackToJava::decodecAvpacket(int size, uint8_t *data) {

    JNIEnv *currentEnv;
    if (javaVM->AttachCurrentThread(&currentEnv, 0) != JNI_OK) {
        LOGE("call onCallInitMediaCodec worng");
    }
    jbyteArray  currentData=currentEnv->NewByteArray(size);
    currentEnv->SetByteArrayRegion(currentData, 0, size, reinterpret_cast<const jbyte *>(data));
    currentEnv->CallVoidMethod(jobj,jmid_decodecAvpacket,size,currentData);

    currentEnv->DeleteLocalRef(currentData);
    javaVM->DetachCurrentThread();
}






